﻿#define TRACE
using System;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Diagnostics;
using UdpTransceiver;
using ParametersParser;
using System.Xml.Linq;
using System.Collections;

using Communicator;
using ArduinoStepper;

/**********************************************
* The module for the control of indicators    *
* of the TL410 air simulator of NAU           *
* Developed by Vladimir Khomenko, 2010        *
**********************************************/

namespace Indicators
{
    using System.Timers;
    /// <summary>
    /// The results of operation
    /// </summary>
    public enum ErrorCodes { OK, Error };
    /// <summary>
    /// Тип индикатора - круговой, угловой, многооборотный 
    /// </summary>
    public enum IndicatorTypes { Dial, Limited, Multirotor };
    /// <summary>
    /// Тип инициализации.
    /// </summary>
    public enum IndicatorInitType { INTERNAL_SENSOR, BY_NETWORK, WITHOUT_SENSOR }
    /// <summary>
    /// Состояния индикатора.
    /// </summary>
    public enum IndicatorStates { Started, PositionRestoring, SensorSearching, 
                                    ReceiverInitialization, DeltaChecking, DeltaReducingCommand, ParameterWaiting, Tracking, 
                                    ZeroCorrection, Fault, Stoped }

    /// <summary>
    /// События индикатора.
    /// </summary>
    public enum IndicatorEvents { Initiated, SensorFound, SensorNotFound, RecordedPositionRestored,
                                    ParameterIsUpdated, DeltaIsMore, DeltaIsLess, DeltaCommandSent,
                                    SensorSet, PositionCorrected, ResetCommand, CriticalError, MotorAngleIsUpdated
    }

    /// <summary>
    /// Представляет обобщенный индикатор 
    /// </summary>
    public abstract class Indicator
    {
        #region Class data members
        /// <summary>
        /// Название индикатора. Читается из конфигуратора
        /// </summary>
        public string Name;
        /// <summary>
        /// Контроллер, к которым управляется индикатор
        /// </summary>
        public Controller Controller;
        public Communicator.Communicator Communicator;
        /// <summary>
        /// Номер мотора, выделенный индикатору и управляемый контроллером
        /// </summary>
        public byte MotorNumber;
        /// <summary>
        /// Тип индикатора
        /// </summary>
        public IndicatorTypes IndicatorType;
        /// <summary>
        /// Значение параметра модели, соответствующее нулевому положению индикатора.
        /// </summary>
        public float ZeroValue = 0f;
        /// <summary>
        /// Коэффициент редукции угла (отношение угла поворота двигателя к углу поворота индикатора)
        /// </summary>
        public float AngleFactor = 1f;
        /// <summary>
        /// Максимальная рабочая скорость поворота индикатора (градусов в секунду)
        /// </summary>
        public float Speed = 0f;
        /// <summary>
        /// Смещение ротора относительно датчика перед точным его поиском 
        /// </summary>
        public float InitialSearchShift = 0f;
        /// <summary>
        /// Максимальный угол поворота индикатора при поиске датчика
        /// </summary>
        public float MaxSearchAngle = 0f;
        /// <summary>
        /// Скорость вращения при поиске датчика (градусов в секунду)
        /// </summary>
        public float SearchSpeed = 0f;
        /// <summary>
        /// Тип инициализации индикатора (Network, internal sensor or without sensor)
        /// </summary>
        public IndicatorInitType InitType;
        /// <summary>
        /// Угловое положение датчика относительно нуля индикатора (устанавливается вручную в конфигураторе)
        /// </summary>
        public float SensorAngle = 0f;
        /// <summary>
        /// Состояние датчика (??????)
        /// </summary>
        public bool SensorState = false;
        /// <summary>
        /// Наименование параметра модели, управляющего индикатором
        /// </summary>
        public string ParName;
        /// <summary>
        /// Текущее значение индикатора.
        /// </summary>
        public float IndicatorValue = 0f;
        /// <summary>
        /// Текущее значение параметра модели.
        /// </summary>
        public float ModelValue = 0f;
        /// <summary>
        /// Состояние индикатора
        /// </summary>
        public IndicatorStates State = IndicatorStates.Started;

        public Thread IndicatorThread;

        internal static SourceSwitch traceSwitch = new SourceSwitch("Indicators") { Level = SourceLevels.Information };
        internal static TraceSource trace = new TraceSource("Indicators") { Switch = traceSwitch };

        protected Timer IndicatorTimer;

        #endregion

        public abstract void CreateStateMachine();
        public abstract void CheckDelta();
        
        public abstract ErrorCodes MoveIndicator(float Value);
        
        public abstract void ReduceDelta();

        /// <summary>
        /// Sets the indicator to the new position
        /// </summary>
        /// <param name="Value">Value of the new position</param>
        /// <returns>Success of error code</returns>
        public abstract ErrorCodes SetIndicator(float Value);

        public abstract void UpdateAngle(object sender, MotorEventArgs e);
        public abstract void UpdateSensor(object sender, SensorsEventArgs e);
        public abstract void UpdateParameter(object sender, EventArgs e);

        /// <summary>
        /// Indicator object constructor
        /// </summary>
        /// <param name="controller">Reference to stepper motor controller</param>
        /// <param name="motorNumber">Number of indicator motor at the controller</param>
        public Indicator(string name, Controller controller, byte motorNumber, Communicator.Communicator communicator)
        {
            this.Name = name;
            this.Controller = controller;
            this.MotorNumber = motorNumber;
            this.Communicator = communicator;

            // Default values
            trace.TraceInformation("Indicator  ");

            // Initiates the trace logger
            //trace.TraceInformation("{0} {1} indicator was created on controller with address {2} on motor# {3}", 
            //                       name, IndicatorType,  Controller.Address, MotorNumber);

            //const string LISTENER_NAME = "DialIndicatorsLog.txt"; // Trace filename
            //textListener = new TextWriterTraceListener(LISTENER_NAME, LISTENER_NAME);
            //Trace.Listeners.Add(textListener);
            // Open the Indicator values log files
            controller.MotorAngleUpdated += new EventHandler<MotorEventArgs>(UpdateAngle);
            controller.FreeSensorChanged += new EventHandler<SensorsEventArgs>(UpdateSensor);
        }

        /// <summary>
        /// Запускает индикатор
        /// </summary>
        public void Start()
        {
            if (Communicator.state != CommunicatorState.active)
                Communicator.Start();
            if (Controller.State != true)
                Controller.Start();
            IndicatorThread = new Thread(this.CreateStateMachine);
            IndicatorThread.Start();
        }

        /// <summary>
        /// Останавливает индикатор
        /// </summary>
        public void Stop()
        {
            Communicator.Stop();
            Controller.Stop();
            IndicatorThread.Abort();
        }       

        /// <summary>
        /// Initialize indicator with the absent zero sensor. Can be used at the testing mode.
        /// </summary>
        /// <returns>Code of success or error</returns>
        public ErrorCodes init_without_sensor()
        {
            IndicatorValue = ZeroValue;
            return ErrorCodes.OK;
        }

        public event EventHandler<SensorFindArgs> SensorSearchCompleted;

        public void OnSensorSearchCompleted(SensorFindArgs e)
        {
            if (SensorSearchCompleted != null)
                SensorSearchCompleted(this, e);
        }

        /// <summary>
        /// Обработчик событий, перебирающий таблицу состояний-переходов и вызывающий необходимые действия
        /// в зависимости от исходного состояния и события
        /// </summary>
        /// <param name="e">Событие, порождающее переход</param>
        protected void HandleStateChangeEvent(IndicatorEvents e)
        {
            // Проходим по списку переходв
            foreach (Transition transition in transitions)
            {
                //Ищем соответствующее начальное состояние и событие
                if (State == transition.startState && e == transition.trigger)
                {

                    Console.WriteLine("Old state = {0}\t, new state = {1}", transition.startState, transition.endState);
                    Console.WriteLine("IndicatorAngle = {0},\t ModelAngle = {1}", this.IndicatorValue, this.ModelValue);
                    trace.TraceEvent(TraceEventType.Information, 10, "Состояние индикатора {0} изменено на {1}", transition.startState, transition.endState);
                    //Устанавливаем следующее состояние
                    State = transition.endState;
                    //Вызываем действия, которые необходимо выполнить при переходе
                    transition.action();
                    // Генерируем событие изменения состояния коммутатора 
                    //if (IndicatorEvent != null)
                    //    IndicatorEvent(this, new IndicatorEventArgs(state, e));

                    break;
                }
            }

        }

        /// Список переходов состояний коммутатора
        /// </summary>
        private IList transitions = new ArrayList();
        /// <summary>
        /// Делегат действий, выполняемых при переходе состояний
        /// </summary>
        protected delegate void IndicatorAction();
        public event EventHandler<IndicatorEventArgs> IndicatorEvent;

        /// <summary>
        /// Adds the new line to the state-transition table. 
        /// Добавление строки переходов в список переходов коммутатора
        /// </summary>
        /// <param name="start">Current state</param>
        /// <param name="e">Event</param>
        /// <param name="end">New state</param>
        /// <param name="action">Action on transition</param>
        protected void AddTransition(IndicatorStates start, IndicatorEvents e, IndicatorStates end, IndicatorAction action)
        {
            // Создаем объект - переход и заполняем его
            transitions.Add(new Transition(start, e, end, action));
        }
        /// <summary>
        /// Представляет один переход 
        /// </summary>
        private class Transition
        {
            public IndicatorStates startState;
            public IndicatorEvents trigger;
            public IndicatorStates endState;
            public IndicatorAction action;

            public Transition(IndicatorStates start, IndicatorEvents e, IndicatorStates end, IndicatorAction a)
            {
                this.startState = start;
                this.trigger = e;
                this.endState = end;
                this.action = a;
            }
        }

    }

    /// <summary>
    /// Represents the type of indicator gage that can revolute 0-360 degree without limiters.
    /// </summary>
    public class DialIndicator: Indicator
    {
        public DialIndicator(string name, Controller Controller, byte MotorNumber, Communicator.Communicator communicator) 
            : base(name, Controller, MotorNumber, communicator) 
        {
            this.IndicatorType = IndicatorTypes.Dial;
        }

        /// <summary>
        /// Init the indicator using internal sensor of the hardware controller 
        /// </summary>
        /// <returns>Code of success or error</returns>
        public void FindSensor()
        {
            // Поворачиваем индикатор в положение поближе к датчику
            SetIndicator(SensorAngle);
            // Если индикатор уже находится в положении датчика, то сдвигаем его против часовой стрелки, чтобы "выбрать" люфт сработки датчика
            if (Controller.Motors[MotorNumber].Sensors[0].State == true)
            {
                SetIndicator(-10);
            }
            // Даем команду на поиска датчика. Если датчик успешно найден
            if (Controller.Motors[this.MotorNumber].FindFreeSensor(MaxSearchAngle) == ErrorCode.OK)
            {
                // Устанавливаем известное уголовое положение датчика как текущее положение индикатора 
                this.IndicatorValue = SensorAngle;
                // Пишем положение индикатора в файл
                XDocument IndicatorsValuesLog = XDocument.Load(Name + ".xml");
                IndicatorsValuesLog.Element("Values").Element(this.Name).SetValue(IndicatorValue.ToString());
                IndicatorsValuesLog.Save(Name + ".xml");
                // Генеририем событие "Датчик найден"
                HandleStateChangeEvent(IndicatorEvents.SensorFound);
            }
            else
            {
                // Генеририем событие "Датчик не найден"
                HandleStateChangeEvent(IndicatorEvents.SensorNotFound);
            }
        }

        /// <summary>
        /// Converts input angle value to normal range 0..360 
        /// </summary>
        /// <param name="value">Any angle in degree</param>
        /// <returns>Angle in 0..360 degree</returns>
        private float convertToDial(float value)
        {
            value = value - 360 * (short)(value / 360); // Normalization to ( value < abs(360) )
            if (value < 0)
                value = 360 + value; // Normalization to ( value = 0..360 )
            return value;
        }
        
        /// <summary>
        /// Addition operation for the normalized angles
        /// </summary>
        /// <param name="a">first angle</param>
        /// <param name="b">second angle</param>
        /// <returns>Sum of angles, normalized to 0..360</returns>
        private float add(float a, float b)
        {
            return convertToDial( a + b );
        }
        
        /// <summary>
        /// Find the difference between two angles that provides the shortest (less than 180) way to move indicator  
        /// </summary>
        /// <param name="a">Current angle</param>
        /// <param name="b">Destination angle</param>
        /// <returns>Delta for moving</returns>
        private float differ (float a, float b)
        {
            float delta = convertToDial( a ) - convertToDial( b );
            if (delta > 180)
                delta = delta - 360;
            else if (delta < -180)
                delta = 360 + delta;

            return delta;
        }

        /// <summary>
        /// Устанавливает индикатор в заданную позицию. Ожидает, пока позиция не будет достигнута
        /// </summary>
        /// <param name="angle">Заданная угловая позиция индикатора</param>
        /// <returns>Success or error code</returns>
        public override ErrorCodes SetIndicator(float angle)
        {
            float AngleDelta;
            float motorAngleDelta;
            ErrorCodes ResultCode = ErrorCodes.OK;
            // Преобразуем значение в диапазон 0..360
            angle = convertToDial(angle);
            // Определяем угловую разницу, на которую необходимо повернуть индикатор
            AngleDelta = differ(angle, IndicatorValue);
            // Определяем угловую разницу, на которую необходимо повернуть двигатель
            motorAngleDelta = AngleDelta * AngleFactor;
            ResultCode = ErrorCodes.OK;
            // Даем команду на поворот двигателя на заданный угол
            Controller.Motors[MotorNumber].SetRelative( motorAngleDelta );
            // Трассируем
            trace.TraceInformation("Indicator " + Name +
                                                  " was set to\tNorm Value = " + angle.ToString() +
                                                  "\tDelta = " + AngleDelta.ToString() +
                                                  "\tStepDelta = " + motorAngleDelta.ToString() +
                                                  "\tInd Value = " + IndicatorValue.ToString() +
                                                  "\tResult" + ResultCode.ToString());
            // Пишем значение индикатора в файл
            XDocument IndicatorsValuesLog = XDocument.Load(Name + ".xml");    
            IndicatorsValuesLog.Element("Values").Element(this.Name).SetValue(IndicatorValue.ToString());
            IndicatorsValuesLog.Save(Name +".xml");
            return ResultCode;
        }

        /// <summary>
        /// Дает команду на перемещение индикатора в заданную позицию. Не ожидает достижения заданной позиции
        /// </summary>
        /// <param name="Value">Необходимая позиция индикатора</param>
        /// <returns>Success or error code</returns>
        public override ErrorCodes MoveIndicator(float Value)
        {
            float AngleDelta;
            float motorAngleDelta;
            ErrorCodes ResultCode = ErrorCodes.OK;
            // Преобразуем значение в диапазон 0..360
            Value = convertToDial(Value);
            // Определяем угловую разницу, на которую необходимо повернуть индикатор
            AngleDelta = differ(Value, IndicatorValue);
            // Определяем угловую разницу, на которую необходимо повернуть двигатель
            motorAngleDelta = AngleDelta * AngleFactor;
            ResultCode = ErrorCodes.OK;

            Controller.Motors[MotorNumber].MoveRelative( motorAngleDelta );
            // Трассируем
            trace.TraceInformation("Indicator " + Name +
                                                  " was set to\tNorm Value = " + Value.ToString() +
                                                  "\tDelta = " + AngleDelta.ToString() +
                                                  "\tStepDelta = " + motorAngleDelta.ToString() +
                                                  "\tInd Value = " + IndicatorValue.ToString() +
                                                  "\tResult" + ResultCode.ToString());
                    // Пишем значение индикатора в журнал
            XDocument IndicatorsValuesLog = XDocument.Load(Name + ".xml");    
            IndicatorsValuesLog.Element("Values").Element(this.Name).SetValue(IndicatorValue.ToString());
            IndicatorsValuesLog.Save(Name +".xml");
            Thread.Sleep(50);
            return ResultCode;
        }

        public event EventHandler<IndicatorEventArgs> CheckDeltaCompleted;

        public void OnCheckDeltaCompleted(IndicatorEventArgs e)
        {
            if (CheckDeltaCompleted != null)
                CheckDeltaCompleted(this, e);
        }

        /// <summary>
        /// Обновление угла поворота индикатора по значению угла поворота двигателя.
        /// </summary>
        /// <param name="motorNumber">Номер двигателя</param>
        /// <returns>Угол поворота индикатора (абсолютный от начальной позиции)</returns>
        public override void UpdateAngle(object sender, MotorEventArgs e)
        {
            if (e.Motor == this.MotorNumber)
                this.IndicatorValue = e.Angle / this.AngleFactor;
            HandleStateChangeEvent(IndicatorEvents.MotorAngleIsUpdated);
        }

        public override void UpdateSensor(object sender, SensorsEventArgs e)
        {
            Boolean prevSensorState = this.SensorState; 
            if (e.Motor == this.MotorNumber)
                this.SensorState = e.State;
            if (prevSensorState == false &&  this.SensorState == true)
                HandleStateChangeEvent(IndicatorEvents.SensorSet);
        }

        /// <summary>
        /// Обновляет значение параметра модели, связанного с индикатором.  
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public override void UpdateParameter(object sender, EventArgs e)
        {
            float prevValue = this.ModelValue;
            this.ModelValue = Convert.ToSingle(Communicator.GetParameterValueByName(this.ParName));
            if (Math.Abs(this.ModelValue - prevValue) > 0.1)
                 HandleStateChangeEvent(IndicatorEvents.ParameterIsUpdated);
        }

        /// <summary>
        /// Проверяет разницу между значением параметра и положением индикатора
        /// </summary>
        /// <param name="Value">The destiantion indicator value</param>
        /// <returns>Success or error code</returns>
        public override void CheckDelta()
        {
            float ValueDelta;
            this.ModelValue = convertToDial(ModelValue);
            ValueDelta = differ(ModelValue, IndicatorValue);
            if (Math.Abs(ValueDelta) >= 1)
               HandleStateChangeEvent(IndicatorEvents.DeltaIsMore);
            else
               HandleStateChangeEvent(IndicatorEvents.DeltaIsLess);
        }
        
 
        public override void ReduceDelta()
        {
            MoveIndicator(this.ModelValue);
            Thread.Sleep(50);
            HandleStateChangeEvent(IndicatorEvents.DeltaCommandSent); 
        }

        private void RestoreRecordedPosition()
        {
            // Открываем файл с последним значнием индикатора во время предыдущей работы - вероятно индикатор остался в том же положении
            XDocument IndicatorValuesLog = XDocument.Load(Name + ".xml");
            // Записываем восстановленное положение индикатора как текущее
            this.IndicatorValue = Convert.ToSingle(IndicatorValuesLog.Element("Values").Element(this.Name).Value);
            HandleStateChangeEvent(IndicatorEvents.RecordedPositionRestored);
        }

       private void InitReceiver()
       {
           Communicator.AddParameter("COURSE", ParameterDirection.input);
           Communicator.DataReceived += new EventHandler<EventArgs>(UpdateParameter);

       }

        private void CorrectZero()
        {
            float valueDelta = this.SensorAngle - this.IndicatorValue;
            if (Math.Abs(valueDelta) > 2)
                SetIndicator(valueDelta);
            HandleStateChangeEvent(IndicatorEvents.PositionCorrected);
        }

        private void Nothing()
        {
            ;
        }

        #region Автомат состояний

        public override void CreateStateMachine()
        {
            //Определение делегатов-действий, выполняемых при переходах состояний
            IndicatorAction restoreRecordedPosition = new IndicatorAction(RestoreRecordedPosition);
            IndicatorAction findSensor = new IndicatorAction(FindSensor);
            IndicatorAction initReceiver = new IndicatorAction(InitReceiver);
            IndicatorAction reduceDelta = new IndicatorAction(ReduceDelta);
            IndicatorAction correctZero = new IndicatorAction(CorrectZero);
            IndicatorAction checkDelta = new IndicatorAction(CheckDelta);
            IndicatorAction nothing = new IndicatorAction(Nothing);
            
            // Заполнение списка переходов состояний по шаблону:
            // начальное состояние / событие / конечное состояние / выполняемые действия
            // Часть таблицы состояний для инициализации и поиска датчика
            AddTransition(IndicatorStates.Started, IndicatorEvents.Initiated , IndicatorStates.PositionRestoring, restoreRecordedPosition);
            AddTransition(IndicatorStates.PositionRestoring, IndicatorEvents.RecordedPositionRestored, IndicatorStates.SensorSearching, findSensor);
            AddTransition(IndicatorStates.SensorSearching, IndicatorEvents.SensorNotFound, IndicatorStates.Fault, nothing);
            // Часть таблицы состояний для слежения
            AddTransition(IndicatorStates.SensorSearching, IndicatorEvents.SensorFound, IndicatorStates.ReceiverInitialization, initReceiver);
            AddTransition(IndicatorStates.ReceiverInitialization, IndicatorEvents.ParameterIsUpdated, IndicatorStates.DeltaChecking, checkDelta);
            AddTransition(IndicatorStates.DeltaChecking, IndicatorEvents.DeltaIsMore, IndicatorStates.DeltaReducingCommand, reduceDelta);
            AddTransition(IndicatorStates.DeltaReducingCommand, IndicatorEvents.DeltaCommandSent, IndicatorStates.ParameterWaiting, nothing);
            AddTransition(IndicatorStates.DeltaChecking, IndicatorEvents.DeltaIsLess, IndicatorStates.ParameterWaiting, nothing);
            AddTransition(IndicatorStates.ParameterWaiting, IndicatorEvents.ParameterIsUpdated, IndicatorStates.DeltaChecking, checkDelta);
            //AddTransition(IndicatorStates.ParameterWaiting, IndicatorEvents.UpdateAngleTime, IndicatorStates.ParameterWaiting, checkAngle);
            // Часть таблицы состояний для коррекции нуля 
            AddTransition(IndicatorStates.ParameterWaiting, IndicatorEvents.SensorSet, IndicatorStates.ZeroCorrection, correctZero);
            AddTransition(IndicatorStates.DeltaChecking, IndicatorEvents.SensorSet, IndicatorStates.ZeroCorrection, correctZero);
            AddTransition(IndicatorStates.DeltaReducingCommand, IndicatorEvents.SensorSet, IndicatorStates.ZeroCorrection, correctZero);
            AddTransition(IndicatorStates.ZeroCorrection, IndicatorEvents.PositionCorrected, IndicatorStates.ParameterWaiting, nothing);           
            // Часть таблицы состояний для ошибок
            AddTransition(IndicatorStates.DeltaReducingCommand, IndicatorEvents.CriticalError, IndicatorStates.Fault, nothing);
            AddTransition(IndicatorStates.Fault, IndicatorEvents.ResetCommand, IndicatorStates.SensorSearching, findSensor);
            AddTransition(IndicatorStates.Fault, IndicatorEvents.SensorSet, IndicatorStates.SensorSearching, findSensor);

            HandleStateChangeEvent(IndicatorEvents.Initiated);

            while (this.State != IndicatorStates.Stoped)
                Thread.Sleep(1);
        }


        #endregion
    }

    // Параметры события окончания поиска датчика
    public class SensorFindArgs : EventArgs
    {
        public Boolean SensorIsFound;
        public SensorFindArgs(Boolean sensorIsFound)
        {
            this.SensorIsFound = sensorIsFound;
        }
    }

    // Параметры события индикатора
    public class IndicatorEventArgs : EventArgs
    {
        IndicatorStates State;
        public Boolean DeltaIsMore;
        public IndicatorEventArgs(IndicatorStates state, Boolean deltaIsMore)
        {
            this.State = state;
            this.DeltaIsMore = deltaIsMore;
        }
    }
/*
    /// <summary>
    /// Represents the type of indicator gage that can do several revolutions (0-360 * n degree, where n = 1,2,3..)
    /// </summary>
        public class MultiRotorIndicator : Indicator
        {
            public MultiRotorIndicator(string name, Controller Controller, MotorSelector MotorNumber)
                : base(name, Controller, MotorNumber)
            {
                this.IndicatorType = IndicatorTypes.MULTIROTOR;
            }

            /// <summary>
            /// Sets indicator according the new parameter value
            /// </summary>
            /// <param name="Value">Value of the parameter associated to indicator</param>
            /// <returns>Code of success or error</returns>
            public override ErrorCodes set_indicator(float Value)
            ///TO DO sync to Dial 
            {
                float ValueDelta;
                short StepDelta;
                ushort AbsSteps;
                ErrorCodes ResultCode;
                // Если индикатор не в состоянии "работа" или "инициализация, то выходим
                if (state != IndicatorStates.Tracing && state != IndicatorStates.ZeroSearching)
                    return ErrorCodes.ERROR;   
                // Steps number calculation
                ValueDelta = Value - IndicatorValue;
                StepDelta = (short)(ValueDelta / ValuePerStep);
                AbsSteps = (ushort)Math.Abs(StepDelta);
                ResultCode = ErrorCodes.OK;
                if (AbsSteps >= 1)
                {
                    //trace.TraceData(TraceEventType.Information, 2, "Motor rotation check = {} ", checkResultCode);
                    if (StepDelta > 0)
                        Controller.Motors[(byte)MotorNumber - 1].Rotate(ForwardRotation, AbsSteps);
                    else
                        Controller.Motors[(byte)MotorNumber - 1].Rotate(ForwardRotation, AbsSteps);
                    
                    do
                    {
                        // Ждем какое-то время
                        Thread.Sleep(10);
                        Controller.SMDGetDevicesStates();
                        // Проверяем, не остановился ли двигатель
                    } while (Controller.Motors[(byte)MotorNumber - 1].State != MotorState.STOPED);
                    // Берем значение счетчика шагов двигателя и определяем фактическое положение инидикатора
                    // с учетом реверсивности его работы
                    if (RotationDirection == Direction.REVERSE)
                        IndicatorValue = Controller.Motors[(byte)MotorNumber - 1].StepCounter * ValuePerStep;
                    else
                        IndicatorValue = -1 * Controller.Motors[(byte)MotorNumber - 1].StepCounter * ValuePerStep;

                    // Трассируем
                    /*trace.TraceInformation("Indicator " + name +
                                                  " was set to\tNorm Value = " + Value.ToString() +
                                                  "\tDelta = " + ValueDelta.ToString() +
                                                  "\tStepDelta = " + StepDelta.ToString() +
                                                  "\tInd Value = " + IndicatorValue.ToString() +
                                                  "\tResult" + ResultCode.ToString()); */
                    // Пишем значение индикатора в журнал
        /*
                    XDocument IndicatorsValuesLog = XDocument.Load(Name + ".xml");
                    IndicatorsValuesLog.Element("Values").Element(this.Name).SetValue(IndicatorValue.ToString());
                    IndicatorsValuesLog.Save(Name + ".xml");
                }
                return ResultCode;
            }
        }
         * */
    }



   
    